home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / PROGRAMM / CC_C / 0151.ZIP / BUGGER.ASM < prev    next >
Assembly Source File  |  1985-09-28  |  41KB  |  2,022 lines

  1. title Fido's Bugger
  2. name bugger
  3. ;
  4. ;****************************************
  5. ;*                    *
  6. ;*            Bugger             *
  7. ;*                    *
  8. ;*    For: Fido            *
  9. ;*                    *
  10. ;*    T. Jennings 20 Oct 83        *
  11. ;*     created 29 April 81        *
  12. ;*                    *
  13. ;****************************************
  14. ;
  15. cgroup group code
  16. dgroup group data
  17. ;
  18. ;   This debugger and boot rom supports the
  19. ;following hardware:
  20. ;
  21. ;Intel SBC 86/12:
  22. ;    Console on the serial port,
  23. ;    9600 baud, no parity, 8 bits
  24. ;Memory:
  25. ;    64K minimum; buggers stack and
  26. ;    work space is at 0f80:0000.
  27. ;    Disk boot sector loaded at 10:0
  28. ;Diskettes:
  29. ;    A Comark MF-85 WD1793 controller,
  30. ;    8" and 5" diskettes.
  31. ;Hard Disk:
  32. ;    A Xebec Controller on a DTC Host
  33. ;    Interface, supporting a typical
  34. ;    10 meg wini, drive type = 4.
  35. ;Other:    A loudspeaker tied to bit 0 of 
  36. ;    the 8255 Port C. 
  37. ;
  38. ;  Bugger inits the hardware needed to boot,
  39. ;some interrupt vectors, then autoboots the
  40. ;hard disk (A:). It makes funny noises while
  41. ;booting.
  42. ;
  43. ;  If Control-C is hit, bugger jumps into
  44. ;command mode; see BUGGER.DOC for details.
  45. ;
  46. ;
  47. ;The power on jump at FFFF:0000 must be
  48. ;patched into the ROMs after burning this
  49. ;code:
  50. ;
  51. ;2716's (2K)
  52. ;
  53. ;EVEN PROM: 07f8: ea 00 fe
  54. ;ODD PROM:  07f8: 00 00
  55. ;
  56. ;2732's (4K)
  57. ;
  58. ;EVEN PROM: 0ff8: ea 00 ff
  59. ;ODD PROM:  0ff8: 00 00
  60. ;
  61. ;What is being patched in is:
  62. ;
  63. ;    jmp far 0fe00:0000 ;(2716)
  64. ;    jmp far 0ff00:0000 ;(2732)
  65. ;
  66. ;Baud rate for the serial port
  67. ;
  68. baud_rate equ    9600    
  69. baud    equ    768 / (baud_rate / 100)
  70. ;
  71. ;Where our data segment is:
  72. ;
  73. dataseg    equ    0f80h
  74. page
  75. ;
  76. ;Interrupts used:
  77. ;
  78. ;
  79. ;Floppy disk read interrupt: A standard Fido
  80. ;disk BIOS table at DS:BX. Status in AL; carry
  81. ;if error. These vectors must be below 00100h,
  82. ;or 0010:0000, since thats where the boot is
  83. ;loaded, and the 1K boot sector wipes out the
  84. ;interrupt vectors.
  85. ;
  86. FLP_INT    equ    32    ;floppy access
  87. RMS_INT    equ    33    ;hard disk access
  88.  
  89. TRC_INT    equ    1    ;single step
  90. BRK_INT    equ    3    ;break point
  91. BRK_INST equ    0cch    ;INT 3
  92. CR    equ    0dh    ;carriage return
  93. LF    equ    0ah    ;line feed 
  94.  
  95. include iodef.ash
  96. include disk.ash
  97. include disk2.ash
  98. page
  99. ;
  100. ;Where we load the boot sector. This is
  101. ;in the middle of the interrupt vectors,
  102. ;and it assumes the boot sector isnt big
  103. ;enough to trash our vectors.
  104. ;
  105. bootseg    segment    at 10h
  106.     org    0
  107. boot label far
  108. bootseg    ends
  109. ;
  110. ;Start of ROM code. cgroup must be
  111. ;first so the linker will put things in
  112. ;the right order.
  113. ;
  114. code segment byte public 'code'
  115. assume cs:cgroup
  116.  
  117. bugger:    jmp    start
  118. ;
  119. ;Old interface. Do not use it.
  120. ;
  121. interface proc far
  122.     call    ina
  123.     ret
  124.     call    outa
  125.     ret
  126.     call    foo        ;deleted call,
  127.     ret            ;dummy out.
  128.     call    execute
  129.     ret
  130.     call    dtc
  131.     ret
  132. ;
  133. ;New interface, accessed by the software
  134. ;interrupts. Call the ROM code,
  135. ;return, trashing the flags.
  136. ;
  137. hboot:    call    dtc
  138.     ret    2
  139.  
  140. fboot:    call    execute
  141.     ret    2
  142.  
  143. interface endp
  144.  
  145. foo:    ret
  146.  
  147. code ends
  148.  
  149. data segment byte public 'data'
  150.  
  151. stack     dw    (?)
  152. ;
  153. ;Work space for the DTC/Xebec controller
  154. ;drivers and initialization.
  155. ;
  156. cmdtbl db 9 dup (?)
  157. dattbl db 8 dup (?)
  158. ;
  159. ;DTC/Xebec command string.
  160. ;
  161. xcomand    db    (?)    ;command,
  162. lun    db    (?)    ;unit, top sector,
  163. hiaddr    db    (?)    ;high sec byte,
  164. lowaddr    db    (?)    ;low sec byte,
  165. scount    db    (?)    ;sector count,
  166. control    db    (?)
  167.     db 8 dup (?)
  168. ;
  169. ;breakpoint and    go register save/display area
  170. ;these register    save locations must be kept in 
  171. ;this order.
  172. ;
  173. dmp_ptr    label word
  174. brkfl    dw    (?)        ;saved flags
  175. brkax    dw    (?)        ;saved ax
  176. brkbx    dw    (?)        ;saved bx
  177. brkcx    dw    (?)        ;saved cx
  178. brkdx    dw    (?)        ;saved dx
  179. brksi    dw    (?)        ;saved si
  180. brkdi    dw    (?)        ;saved di
  181. brksp    dw    (?)        ;saved sp
  182. brkip    dw    (?)        ;saved ip
  183. ip_base    dw    (?)        ;reloc reg
  184. brkcs    dw    (?)
  185. brkds    dw    (?)
  186. brkes    dw    (?)
  187. brkss    dw    (?)
  188. brkbp    dw    (?)        ;base pointer
  189. ;
  190. ;More data area. These don't have to be in
  191. ;any specific order.
  192. ;
  193. noreloc    db    (?)        ;no relocation
  194. dmpoff    dw    (?)        ;display addr
  195. dmpseg    dw    (?)        ;local ES
  196. scratch    db    (?)        ;scratch word,
  197. bootnum    dw    (?)        ;default drive,
  198. ;
  199. ;Breakpoint data.
  200. ;
  201. brkflg    db    (?)        ;true if break
  202. brkadr    dw    (?)        ;brk pnt addr
  203. brkseg    dw    (?)        ;brk pnt seg
  204. brkinst    db    (?)        ;saved inst
  205. data ends
  206.  
  207. page
  208. code segment byte public 'code'
  209. assume cs:cgroup,ds:dgroup
  210. ;
  211. ;Data word to set DS.
  212. ;
  213. dataloc    dw    dataseg
  214. ;
  215. ;Data tables here, to avoid MASM bugs.
  216. ;
  217. ctable    db      'g'
  218.     dw    offset go
  219.     db    'x'
  220.     dw    offset registers;dump regs
  221.     db    'r'
  222.     dw    offset registers
  223.     db    's'
  224.     dw    offset memchg    ;change    memory
  225.     db    'e'
  226.     dw    offset memchg    ;ditto
  227.     db    'd'
  228.     dw    offset dump    ;dump memory
  229.     db    'f'
  230.     dw    offset fill    ;fill memory,
  231.     db    'm'
  232.     dw    offset blkmov    ;move memory.
  233.     db    'i'
  234.     dw    offset input    ;port input
  235.     db    'o'
  236.     dw    offset output    ;port output.
  237.     db    't'
  238.     dw    offset trace    ;trace command,
  239.     db    'h'
  240.     dw    offset arith    ;do arithmetic
  241.     db    'l'
  242.     dw    offset intel    ;load hex,
  243.     db    'v'
  244.     dw    offset intvec    ;fiddle int vec
  245.     db    'b'
  246.     dw     offset dboot    ;disk boot
  247. tlen    equ    ($ - ctable) / 3
  248. page
  249. eh    db    ' eh?',0
  250. id1str    db CR,"Fido, 1 December 84"
  251. id2str    db CR,"Booting from drive A:, "
  252.     db " Control-C to abort: ",0
  253. dskstr    db CR,"Disk read error",0
  254. butstr    db CR,"Bad boot sector",0
  255.  
  256. prompt    db    CR,'Ok.',0
  257.  
  258. regstr1    db CR,'ax   bx   cx   dx   si   di   '
  259.     db    'sp   ip + rr   ',CR,0
  260.  
  261. regstr2    db CR,'cs   ds   es   ss   bp   TOS  '
  262.     db    'NOS  ....oditsz.a.p.c',CR,0
  263.  
  264. regtbl    dw    'fl','ax','bx','cx','dx','si'
  265.     dw    'di','sp','ip','rr','cs'
  266.     dw    'ds','es','ss','bp'
  267. rtblen    equ    ($ - regtbl) / 2
  268.  
  269. page
  270. ;
  271. ;Disk boot read    tables. These are the
  272. ;standard Fido MSDOS BIOS disk tables. All
  273. ;boot sectors are track 0 sector 1. (First
  274. ;sector, damn IBM)
  275. ;
  276. ;Shugart 850, drive 0, DD1024 single sided,
  277. ;double density, eight 1024 byte sectors, 
  278. ;77 tracks.
  279. ;
  280. dd1024    db    fread    ;read command, 
  281.     db    0    ;drive 0,
  282.     dw    0    ;track 0,
  283.     dw    1    ;sector    1,
  284.     dw    1    ;1 sector,
  285.     dw    -1    ;current track unknown
  286.     db    1    ;double density,
  287.     db    15    ;gap length,
  288.     db    3    ;sec size,
  289.     db    255    ;data len,
  290.     dw    1024    ;sector    size,
  291.     dw    0    ;DMA offset,
  292.     dw    10h    ;DMA segment,
  293.     dw    8    ;sectors/track
  294.     dw    0    ;head 0,
  295. dblen equ $ - dd1024
  296. ;
  297. ;Shugart 850, SD128 single sided single
  298. ;density 26 128 byte sectors per track.
  299. ;
  300. sd128    db    fread    ;read command, 
  301.     db    0    ;drive 0,
  302.     dw    0    ;track 0,
  303.     dw    1    ;sector    1,
  304.     dw    1    ;1 sector,
  305.     dw    -1    ;current track unknown
  306.     db    0    ;single density,
  307.     db    0    ;gap length,
  308.     db    0    ;sec size,
  309.     db    0    ;data len,
  310.     dw    128    ;sector    size,
  311.     dw    0    ;DMA offset,
  312.     dw    10h    ;DMA segment,
  313.     dw    26
  314.     dw    0
  315. ;
  316. ;Tandon DMIBM8-1 single sided double density
  317. ;eight 512 byte sectors per track, 40 tracks.
  318. ;
  319. ibm    db    fread    ;read command, 
  320.     db    2    ;drive 2,
  321.     dw    0    ;track 0,
  322.     dw    1    ;sector    1,
  323.     dw    1    ;1 sector,
  324.     dw    -1    ;current track unknown
  325.     db    3    ;double density mini
  326.     db    0    ;gap length,
  327.     db    0    ;sec size,
  328.     db    0    ;data len,
  329.     dw    512    ;sector    size,
  330.     dw    0    ;DMA offset,
  331.     dw    10h    ;DMA segment,
  332.     dw    8    ;spt
  333.     dw    0    ;head
  334. page
  335. ;RMS, HD256 8 heads 32 256 byte sectors/track,
  336. ;logically arranged as 192 spt.
  337. ;
  338. rms    db    fread    ;read command, 
  339.     db    0    ;drive 0,
  340.     dw    0    ;track 0,
  341.     dw    1    ;sector    1,
  342.     dw    1    ;1 sector,
  343.     dw    -1    ;current track unknown
  344.     db    0
  345.     db    0    ;gap length,
  346.     db    0    ;sec size,
  347.     db    0    ;data len,
  348.     dw    256    ;sector    size,
  349.     dw    0    ;DMA offset,
  350.     dw    10h    ;DMA segment,
  351.     dw    192    ;spt
  352.     dw    0
  353. ;
  354. ;Same as above, table for interrogating
  355. ;drive ready only.
  356. ;
  357. rmsc    db    fcheck    ;read command, 
  358.     db    0    ;drive 0,
  359.     dw    0    ;track 0,
  360.     dw    1    ;sector    1,
  361.     dw    1    ;1 sector,
  362.     dw    -1    ;current track unknown
  363.     db    0
  364.     db    0    ;gap length,
  365.     db    0    ;sec size,
  366.     db    0    ;data len,
  367.     dw    256    ;sector    size,
  368.     dw    0    ;DMA offset,
  369.     dw    10h    ;DMA segment,
  370.     dw    192    ;spt
  371.     dw    0    ;head
  372. page
  373. ;
  374. ;Sound tables, for a 8253 clock rate
  375. ;of 1.23 MHz.
  376. ;
  377. OCTAVE    equ    2
  378.  
  379. CNOTE    equ    9609    ;C
  380. CSNOTE    equ    9044    ;C#
  381. DNOTE    equ    8541    ;D
  382. DSNOTE    equ    8092    ;D#
  383. ENOTE    equ    7687    ;E
  384. FNOTE    equ    6988    ;F
  385. FSNOTE    equ    6684    ;F#
  386. GNOTE    equ    6406    ;G
  387. GSNOTE    equ    5913    ;G#
  388. ANOTE    equ    5694    ;A
  389. ASNOTE    equ    5301    ;A#
  390. BNOTE    equ    4959    ;B
  391. NONOTE    equ    0    ;no tone
  392. ENDNOTE    equ    -1    ;end of list
  393.  
  394. EIGHTH    equ    20
  395. QUARTER    equ    2 * EIGHTH
  396. HALF    equ    2 * QUARTER
  397. FULL    equ    2 * HALF
  398. ;
  399. ;Something wrong
  400. ;
  401. fault label word
  402.     dw    NONOTE,QUARTER
  403.     dw    DNOTE,QUARTER
  404.     dw    DSNOTE,HALF
  405.     dw    CNOTE,QUARTER
  406.     dw    CSNOTE,HALF
  407.     dw    DNOTE,QUARTER
  408.     dw    DSNOTE,HALF
  409.     dw    CNOTE,QUARTER
  410.     dw    CSNOTE,HALF
  411.     dw    ENDNOTE
  412. ;
  413. ;Power up, alive.
  414. ;
  415. alive label word
  416.     dw    CNOTE,QUARTER
  417.     dw    ANOTE,QUARTER
  418.     dw    GNOTE,QUARTER
  419.     dw    ENOTE,QUARTER
  420.     dw    NONOTE,QUARTER
  421.     dw    CNOTE,QUARTER
  422.     dw    ANOTE,QUARTER
  423.     dw    GNOTE,QUARTER
  424.     dw    ENOTE,QUARTER
  425.     dw    NONOTE,QUARTER
  426.     dw    ENDNOTE
  427. ;
  428. ;While trying to boot
  429. ;
  430. bootsong label word
  431.     dw    ANOTE,HALF
  432.     dw    FSNOTE,HALF
  433.     dw    ENOTE,HALF
  434.     dw    DNOTE,HALF
  435.     dw    NONOTE,HALF
  436.     dw    ENDNOTE
  437. ;
  438. ;Boot loaded, running DOS
  439. ;
  440. dostune label word
  441.     dw    CNOTE,QUARTER
  442.     dw    DNOTE,QUARTER
  443.     dw    ENOTE,QUARTER
  444.     dw    FNOTE,QUARTER
  445.     dw    GNOTE,QUARTER
  446.     dw    BNOTE,QUARTER
  447.     dw    ENDNOTE
  448. ;
  449. ;Bugger command error
  450. ;
  451. blatz label word
  452.     dw    DNOTE,EIGHTH
  453.     dw    DSNOTE,EIGHTH
  454.     dw    CNOTE,EIGHTH
  455.     dw    CSNOTE,EIGHTH
  456.     dw    ENDNOTE
  457. page
  458. ;
  459. ;Set things up, init the hardware, try
  460. ;to boot.
  461. ;
  462. start:    mov    ss,cs:dataloc
  463.     mov    sp,offset stack
  464.     mov    ds,cs:dataloc
  465.  
  466.     call    IOINIT        ;clear hardware
  467.     mov    bx,offset alive
  468.     call    play        ;make noise
  469.  
  470.     mov    ax,0
  471.     mov    ds,ax        ;install int
  472.  
  473.     mov    bx,BRK_INT * 4
  474.     mov    word ptr [bx],offset brkntr
  475.     mov    bx,BRK_INT * 4 + 2
  476.     mov    word ptr [bx],cs
  477.     mov    bx,TRC_INT * 4
  478.     mov    word ptr [bx],offset brkntr
  479.     mov    bx,TRC_INT * 4 + 2
  480.     mov    word ptr [bx],cs
  481.     mov    bx,FLP_INT * 4
  482.     mov    word ptr [bx],offset fboot
  483.     mov    bx,FLP_INT * 4 + 2
  484.     mov    word ptr [bx],cs
  485.     mov    bx,RMS_INT * 4
  486.     mov    word ptr [bx],offset hboot
  487.     mov    bx,RMS_INT * 4 + 2
  488.     mov    word ptr [bx],cs
  489.  
  490.     mov    ds,cs:dataloc
  491.     mov    ip_base,0
  492.     mov    brkflg,0
  493.     mov    brkds,ds
  494.     mov    brkss,ss
  495.     mov    brksp,sp
  496.  
  497.     mov    bx,offset id1str
  498.     call    pstr
  499. ;
  500. ;Wait until the disk is ready, then boot it.
  501. ;If Control-C is typed, jump into bugger.
  502. ;
  503.     mov    ax,cs        ;disk tables in
  504.     mov    ds,ax        ;code seg
  505. b11:    mov    bx,offset bootsong
  506.     call    play        ;chance to hit
  507.     call    inastat        ;a key to quit
  508.     jz    b13
  509. b12:    call    ina        ;flush all keys
  510.     call    inastat
  511.     jnz    b12
  512.     mov    bx,offset fault    
  513.     call    play        ;make noise
  514.     jmp    warm        ;exit 
  515.  
  516. b13:    mov    bx,offset rmsc    ;check for
  517.     int    RMS_INT        ;drive ready
  518.     jc    b11
  519.  
  520.     mov    bx,offset rms    ;attempt to 
  521.     int    RMS_INT        ;read the boot
  522.     jnc    b20
  523.     mov    bx,offset dskstr;if error,
  524.     call    pstr        ;nasty message
  525.     mov    bx,offset fault
  526.     call    play
  527.     jmp    b11
  528.  
  529. b20:    mov    ax,bootseg    ;read OK,
  530.     mov    ds,ax        ;make sure it's
  531.     mov    bx,0        ;really a boot
  532.     mov    al,[bx]        ;sector,
  533.     cmp    al,0fah        ;(CLI)
  534.     je    b21        ;if not,
  535.     mov    bx,offset butstr
  536.     call    pstr
  537.     mov    bx,offset fault
  538.     call    play
  539.     jmp    b11
  540.  
  541. b21:    mov    bx,offset dostune
  542.     call    play
  543.     mov    cx,0        ;drive A:,
  544.     jmp    boot        ;boot system.
  545. page
  546. ;
  547. ;This is the main command loop,    where commands 
  548. ;are input, etc. Any user type errors get here 
  549. ;also. Some commands that cannot maintain stack
  550. ;discipline, such as return from break point, 
  551. ;jump here. Look up single letter commands 
  552. ;input from the    console, in the    command    table.
  553. ;If we find one, go execute it,    else barf.
  554. ;
  555. warm:    mov    ss,cs:dataloc
  556.     mov    sp,offset stack
  557.     mov    ds,cs:dataloc    ;set our DS,
  558.     mov    es,dmpseg    ;and ES,
  559. wig:    mov    bx,offset prompt ;type prompt,    
  560.     call    pstr        ;string in CS:
  561.     call    charin        ;get command 
  562.     jz    wig        ;ignore    delims
  563.     mov    bx,offset ctable;table search,
  564.     mov    cx,tlen        ;table length,
  565. warma:    cmp    al,cs:[bx]    ;find it?
  566.     je    warmbh        ;yup.
  567.     add    bx,3
  568.     loop    warma
  569.     jmp    error        ;nope
  570. warmbh:                ;command match
  571.     mov    cx,cs:[BX+1]    ;get out addr
  572.     call    cx        ;call it,
  573.     jmp    warm        ;repeat.
  574. ;
  575. ;General purpose error handler.    not real 
  576. ;graceful.
  577. ;
  578. error:    mov    bx,offset eh    ;nasty msg,
  579.     call    pstr
  580.     mov    bx,offset blatz
  581.     call    play
  582.     jmp    warm
  583. page
  584. ;
  585. ;Trace command.    Set the    Trace flag in the flag
  586. ;register, then    execute like a 'go'.
  587. ;
  588. trace:    or    brkfl,0000000100000000b
  589.     jmp    gonow        ;go execute,
  590. ;
  591. ;Go with or without breakpoint. If a comma is
  592. ;entered, get a breakpoint address, else just
  593. ;execute.
  594. ;
  595. go:    and    brkfl,1111111011111111b
  596.     mov    es,brkcs    ;set 'go' seg
  597.     mov    dmpseg,es    ;and in ES,
  598.     mov    bx,brkip    ;and 'go' off
  599.     mov    dmpoff,bx
  600.     call    getadr        ;for 'getadr'
  601.     mov    brkip,bx    ;set brk IP,
  602.     mov    brkcs,es    ;and seg,
  603.     cmp    al,','        ;if a comma, 
  604.     jne    gonow        ;breakpoint,
  605. ;
  606. ;The start addr is set, and a comma was typed.
  607. ;Get the breakpoint addr, put an INT 3 there
  608. ;and save the instruction.
  609. ;
  610. gobrk:    call    getadr        ;get brk addr
  611.     mov    brkadr,bx    ;save brk adr
  612.     mov    brkseg,es
  613.     mov    al,BRK_INST
  614.     xchg    al,es:[bx]    ;set brk inst,
  615.     mov    brkinst,al    ;save old inst
  616.     mov    brkflg,1    ;set flag,
  617. ;
  618. ;Restore regs and return.
  619. ;
  620. gonow:    cli            ;no ints,
  621.     mov    ax,brkax
  622.     mov    bx,brkbx    ;restore a
  623.     mov    cx,brkcx    ;bunch of regs
  624.     mov    dx,brkdx
  625.     mov    di,brkdi
  626.     mov    si,brksi
  627.     mov    bp,brkbp
  628.     mov    ss,brkss    ;set SS and
  629.     mov    sp,brksp    ;stack pointer,
  630.     push    brkfl        ;push flags,
  631.     push    brkcs        ;far address,
  632.     push    brkip
  633.     mov    es,brkes    ;restore ES,
  634.     mov    ds,brkds    ;and DS,
  635.     iret            ;call address
  636. page
  637. ;
  638. ;Breakpoint entry. Executed only via a jump 
  639. ;from the restart location.  Breakpoints 
  640. ;require lots of the users stack. All registers
  641. ;are saved and displayed. 
  642. ;
  643. ;Decrement the go counter; if not zero yet,
  644. ;display the regs and go reexecute from there.
  645. ;
  646. brkntr:    push    ds
  647.     mov    ds,cs:dataloc    ;set DS,
  648.     pop    brkds        ;save DS,
  649.     pop    brkip        ;IP,
  650.     pop    brkcs        ;CS,
  651.     pop    brkfl        ;flags,
  652.  
  653.     mov    brkax,ax    ;save regs,
  654.     mov    brkbx,bx
  655.     mov    brkcx,cx
  656.     mov    brkdx,dx
  657.     mov    brksi,si
  658.     mov    brkdi,di
  659.     mov    brkbp,bp
  660.     mov    brkes,es
  661.     mov    brkss,ss
  662.     mov    brksp,sp
  663.  
  664.     mov    ss,cs:dataloc    ;set stack,
  665.     mov    sp,offset stack
  666.     sti            ;enable ints,
  667.  
  668.     mov    ax,brkip    ;set variables
  669.     mov    dmpoff,ax    ;for debug,
  670.     mov    ax,brkcs
  671.     mov    dmpseg,ax
  672.  
  673.     test    brkflg,1    ;breakpoint?
  674.     jz    bknbh        ;return if not.
  675.         dec    brkip    ;put pc    back 
  676.         mov    bx,brkadr ;restore the
  677.         mov    es,brkcs  ;instruction
  678.         mov    al,brkinst
  679.         mov    es:[bx],al
  680. bknbh:    mov    brkflg,0    ;no more brkpt
  681.     call    regdmp        ;dump the regs
  682.     jmp    warm        ;and stop.
  683. page
  684. ;
  685. ;Register control command. X<CR,comma,space> 
  686. ;displays  all registers.  X<reg name> displays
  687. ;the current register value, and allows    
  688. ;entering al new value.    The legal register 
  689. ;names are in al table in the byte section.     
  690. ;
  691. registers:
  692.     call    charin
  693.     je    regdmp        ;Z set if delim
  694.     jmp    regchg        ;if not    a delim
  695. regdmp:    mov    bx,offset regstr1 ;type    top lin
  696.     call    pstr        ;of the display
  697.     mov    bx,brkax
  698.     call    outhex        ;type ax,    
  699.     mov    bx,brkbx
  700.     call    outhex        ;type bx,space
  701.     mov    bx,brkcx
  702.     call    outhex        ;type cx,space
  703.     mov    bx,brkdx
  704.     call    outhex        ;type bx,spaces
  705.     mov    bx,brksi
  706.     call    outhex        ;si, spaces,
  707.     mov    bx,brkdi
  708.     call    outhex        ;di, spaces,
  709.     mov    bx,brksp
  710.     call    outhex        ;type sp
  711.     mov    bx,brkip    ;type IP,
  712.     sub    bx,ip_base    ;minus offset,
  713.     call    outhex
  714.  
  715.     mov    bx,ip_base
  716.     call    outhex        ;reloc reg,
  717.  
  718.     mov    bx,offset regstr2 ;next    line,
  719.     call    pstr
  720.     mov    bx,brkcs    ;type seg regs
  721.     call    outhex
  722.     mov    bx,brkds
  723.     call    outhex
  724.     mov    bx,brkes
  725.     call    outhex
  726.     mov    bx,brkss
  727.     call    outhex
  728.     mov    bx,brkbp    ;and the BP reg
  729.     call    outhex
  730.  
  731.     mov    es,brkss    ;get two top 
  732.     mov    si,brksp    ;stack values,
  733.     cld
  734.     mov    bx,es:[si]
  735.     call    outhex        ;type TOS,
  736.     mov    bx,es:[si+2]
  737.     call    outhex        ;then NOS,
  738.  
  739.     mov    ax,brkfl
  740.     call    axtobin        ;type flags,
  741.     ret
  742. page
  743. ;
  744. ;Modify    pseudo registers. The registers    are 
  745. ;hardcoded in the same order as they appear in
  746. ;RAM. AL contains the first letter of the 
  747. ;register, get the second letter in AH,    then 
  748. ;look it up.    
  749. ;
  750. regchg:    mov    ah,al
  751.     call    charin
  752.     cmp    ax,'ip'        ;special case
  753.     je    regip        ;IP,
  754.  
  755.     mov    si,offset regtbl ;reg names,
  756.     mov    bx,offset dmp_ptr; reg values,
  757.     mov    cx,rtblen    ;table length,
  758. rchal:    cmp    ax,cs:[si]    ;match?
  759.     je    pair        ;go change.
  760.     add    si,2        ;next...
  761.     add    bx,2
  762.     loop    rchal
  763.     jmp    ERROR        ;none!
  764. ;
  765. ;Change    a word in memory.
  766. ;
  767. pair:    mov    cx,[bx]        ;get value,
  768.     xchg    bx,cx        ;to BX,
  769.     call    xreg        ;change it,
  770.     xchg    cx,bx        ;to CX,
  771.     mov    [bx],cx        ;update.
  772.     ret
  773. ;
  774. ;Display a value, and get a new    one.
  775. ;
  776. xreg:    call    outhex        ;display it,
  777.     mov    al,'='
  778.     call    charout
  779.     call    inhex        ;get a new one.
  780.     ret
  781. ;
  782. ;Register IP. Display current IP minus 
  783. ;'ip_base', add it in when storing it.
  784. ;
  785. regip:    mov    bx,brkip
  786.     sub    bx,ip_base    ;adjust,
  787.     call    xreg        ;change,
  788.     add    bx,ip_base    ;adjust again,
  789.     mov    brkip,bx    ;store.
  790.     ret
  791. page
  792. ;
  793. ;display memory    as 8 lines of 16 bytes,
  794. ;followed by 16    of ASCII. es: is our data 
  795. ;segment pointer.
  796. ;
  797. dump:    call    getadr        ;get address,
  798.     mov    cx,8        ;do i= 1,8
  799. dmpal:        call    crlf    ;newline,
  800.         call    outadr    ;type addr,
  801.         push    cx    ;save count,
  802.         mov    cx,16    ;do j=1,16
  803.         push    bx    ;save for ASCII
  804. dmpbh:            mov    al,es:[bx]
  805.             call    out2h
  806.             inc    bx
  807.             mov    dmpoff,bx
  808.         loop    dmpbh    ;do 16 bytes
  809.  
  810.         pop    bx    ;now dump ASCII
  811.         mov    cx,16
  812. dmpbl:            mov    al,es:[bx]
  813.             inc    bx ;same bytes,
  814.             and    al,7fh
  815.             cmp    al,' '
  816.             jae    dmpd
  817.             mov    al,'_'
  818. dmpd:            call    charout
  819.         loop    dmpbl
  820.     pop    cx        ;get line count
  821.     loop    dmpal        ;next line,
  822.     ret
  823. page
  824. ;
  825. ;Examine/change    memory.    An address is entered, 
  826. ;and  bytes are    displayed after    the address. 
  827. ;New values may    be entered, or the left    
  828. ;unchanged by typing only al delimiter.    Comma 
  829. ;and space close the current location, and open
  830. ;the next  location. A <CR> closes the current 
  831. ;location and quits. Typing bad hex aborts the 
  832. ;current location.
  833. ;
  834. memchg:
  835.     call    getadr        ;get start addr
  836. memal:    call    crlf
  837.     call    outadr        ;type address,
  838.     mov    dmpoff,bx    ;save addr,
  839.     mov    al,es:[bx]    ;get old,
  840.     call    out2h        ;type old,
  841.     mov    al,es:[bx]
  842.     mov    bl,al        ;put old in bl,
  843.     call    inhex        ;maybe get new,
  844.     mov    dh,bl        ;put new in dh,
  845.     mov    bx,dmpoff    ;get addr again
  846.     mov    es:[bx],dh    ;write to mem
  847.     cmp    al,CR        ;was char a CR?
  848.     jz    sret        ;exit    if so.
  849.     inc    bx        ;next location.
  850.     cmp    al,LF        ;if it was LF, 
  851.     jnz    memal        ;dec instead of
  852.     dec    bx        ;incrementing.
  853.     dec    bx
  854.     jmp    memal
  855. sret:    ret
  856. page
  857. ;
  858. ;fill memory with al number. get two addresses,
  859. ;then the filler. Cannot fill across segment
  860. ;boundaries.
  861. ;
  862. fill:    cld
  863.     call    getadr
  864.     call    inhex        ;get 2nd addr
  865.     cmp    al,':'        ;dont allow 2nd
  866.     jne    fllok        ;segment,
  867.         jmp    error    ;count 64k max.
  868. fllok:    mov    cx,dmpoff    ;cx is lo addr,
  869.     sub    bx,cx        ;bx is hi addr,
  870.     xchg    bx,cx        ;cx is count, 
  871.     push    bx        ;bx is lo addr
  872.     call    ghex0        ;get fill char,
  873.     mov    al,bl
  874.     pop    di        ;get addr,
  875.     jcxz    sret        ;dont do none,
  876.     rep stosb        ;do it.
  877.     ret
  878. ;
  879. ;Move a block of memory. Get the <from>, <end>
  880. ;and <to> addresses, calculate the block length
  881. ;then move it. Moves correctly across segments.
  882. ;
  883. blkmov:    cld
  884.     call    getadr        ;get from,
  885.     mov    dx,ES        ;save seg,
  886.     mov    si,bx
  887.     call    inhex        ;get end,
  888.     cmp    al,':'        ;dont allow a
  889.     jne    blk1        ;segment here,
  890.         jmp    error    ;error!
  891. blk1:    mov    cx,si
  892.     sub    bx,cx        ;cnt=end-from
  893.     mov    cx,bx
  894.     call    getadr        ;get to,
  895.     mov    di,bx        ;ES is dest seg
  896.     push    ds        ;save our DS
  897.     mov    ds,dx        ;set our temp
  898.     rep movsb         ;source    segment
  899.     pop    ds        ;restore DS
  900.     ret
  901. page
  902. ;
  903. ;Port I/O commands. These do 16    bit I/O    ports,
  904. ;but only 8 bit    data.
  905. ;
  906. ;    Input data from a port.
  907. ;
  908. input:
  909.     call    ghex0        ;get port num
  910.     mov    dx,bx
  911.     in    al,dx        ;read the port,
  912.     push    ax
  913.     call    crlf
  914.     pop    ax
  915.     push    ax
  916.     call    out2h        ;display in hex
  917.     pop    ax
  918.     call    altobin        ;then in binary
  919.     ret
  920.  
  921. ;
  922. ;    Output data to a port.
  923. ;
  924. output:
  925.     call    ghex0        ;get port num
  926.     mov    dx,bx
  927.     call    ghex0        ;get the data,
  928.     mov    ax,bx
  929.     out    dx,al        ;send it.
  930.     ret
  931. ;
  932. ;Do some simple    hex arithmetic.    Input an 
  933. ;expression, display the result.
  934. ;
  935. arith:    call    inhex        ;get the number
  936.     call    crlf        ;newline,
  937.     call    outhex        ;display result
  938.     ret
  939. page
  940. ;
  941. ;Load an intel hex file    from the console. This 
  942. ;does not support any extended hex format; just
  943. ;the old fashioned 8 bit hex. The segment is 
  944. ;input from the    console.
  945. ;
  946. intel:    mov    dmpoff,0    ;set defaults,
  947.     mov    dmpseg,40h
  948.     call    getadr        ;get load seg,
  949.     mov    es,dmpseg
  950. ;
  951. ;Load each hex record to segment ES, with an 
  952. ;offset    of (dmpoff)( i.e. added    to the specifie
  953. ;load address every time)
  954. ;
  955. getrcd:    call    charin        ;wait for colon
  956.     cmp    al,':'
  957.     je    iproc
  958.     cmp    al,LF        ;if LF, echo it
  959.     jne    getrcd
  960.     call    charout
  961.     jmp    getrcd
  962.  
  963. iproc:    mov    dx,0        ;clear checksum
  964.     call    in2        ;get the count,
  965.     mov    cl,bl        ;put in    CX,
  966.     mov    ch,0
  967.     call    in2        ;get load addr
  968.     mov    al,bl        ;save hi addr,
  969.     call    in2
  970.     mov    bh,al        ;assemble word,
  971.     mov    di,bx        ;put in    DI,
  972.     call    in2        ;record type,
  973.     cmp    bl,1        ;EOF?
  974.     jz    itret        ;return    if so,
  975.     jcxz    itret        ;or if no data,
  976. ;
  977. ;Read <CX> bytes to memory.
  978. ;
  979.     add    di,dmpoff    ;add in    offset,
  980. getb:    call    in2        ;get a byte,
  981.     mov    es:[di],bl    ;store it,
  982.     inc    di        ;next address,
  983.     loop    getb
  984.     call    in2        ;get check sum,
  985. ;
  986. ;checksum broken. Too lazy to fix it.
  987. ;
  988. ;    add    dl,bl        ;if OK,
  989. ;    jz    getrcd        ;repeat,
  990.     jmp    getrcd        ;patch fix.
  991.  
  992. iterr:    jmp    error        ;else error.
  993. itret:    ret
  994. page
  995. ;
  996. ;INTEL,    continued.
  997. ;
  998. ;
  999. ;Input the next    two digits as hex, return in 
  1000. ;BL. Accumulate    a checksum in DX, preserve 
  1001. ;AX, CX.
  1002. ;
  1003. in2:    push    ax
  1004.     push    cx
  1005.     mov    bx,0
  1006.     call    charin        ;get a char,
  1007.     call    hexin        ;install char,
  1008.     jb    iterr
  1009.     call    charin
  1010.     call    hexin
  1011.     jb    iterr
  1012.     pop    cx
  1013.     pop    ax
  1014.     add    dl,bl        ;checksum
  1015.     ret    
  1016. page
  1017. ;
  1018. ;Examine/change an interrupt vector. The
  1019. ;input number is checked for 0-ff, the 
  1020. ;address of it made, the contents displayed.
  1021. ;The contents can be changed by typing in
  1022. ;the new seg:off, or CR to leave unchanged.
  1023. ;
  1024. intvec:    call    ghex0        ;get int num,
  1025.     call    crlf        ;newline,
  1026.     and    bx,255        ;0-255,
  1027.     shl    bx,1        ;times 2,
  1028.     shl    bx,1        ;times 4,
  1029.     mov    ax,0
  1030.     mov    es,ax        ;seg 0,
  1031.     push    bx        ;save vec addr
  1032.     push    es        ;in es:BX,
  1033.     push    ip_base        ;relocation
  1034.     mov    ip_base,0    ;off,
  1035.     call    outadr        ;display addr,
  1036.  
  1037.     mov    ax,es:[bx+2]    ;get int seg,
  1038.     mov    bx,es:[bx]    ;get int off,
  1039.     mov    es,ax        ;to es:BX 
  1040.  
  1041.     mov    dmpseg,es    ;Set default
  1042.     mov    dmpoff,bx    ;for 'getadr',
  1043.     call    outadr        ;display it,
  1044.     call    getadr        ;get new,
  1045.     mov    cx,es        ;copy es:BX to 
  1046.     mov    dx,bx        ;CX:DX,
  1047.  
  1048.     pop    ip_base        ;restore reloc,
  1049.     pop    es        ;get back int
  1050.     pop    bx        ;vector addr,
  1051.     mov    es:[bx+2],cx    ;store new
  1052.     mov    es:[bx],dx    ;vector.
  1053.     ret
  1054. page
  1055. ;
  1056. ;Boot either a hard disk or floppy. Get either
  1057. ;'f', 'h' or 'm', then a number. Attempt to 
  1058. ;read the boot sector to memory, then execute 
  1059. ;it, unless the number has bit 15 set.
  1060. ;
  1061. dboot:    call    charin        ;get disk,
  1062.     mov    si,offset btbl    ;search table
  1063. db1:    cmp    al,cs:[si]    ;find it?
  1064.     je    db2
  1065.     add    si,blen        ;no, next..
  1066.     cmp    byte ptr cs:[si],0
  1067.     jne    db1        ;no more?
  1068.     jmp    error
  1069.  
  1070. db2:    call    ghex0        ;get number,
  1071.  
  1072.     mov    ax,cs        ;disk tables
  1073.     mov    ds,ax        ;in code seg
  1074.     push    bx        ;save it,
  1075.     mov    bx,cs:[si + 1]    ;disk table
  1076.     call    word ptr cs:[si + 3] ;read disk
  1077.     pop    cx
  1078.     mov    ds,cs:dataloc    ;set DS
  1079.     mov    bx,offset dskstr
  1080.     jc    db4        ;if OK,
  1081.  
  1082.     test    cx,8000h    ;and MSB set,
  1083.     jz    db3
  1084.     jmp    warm        ;dont boot
  1085. db3:    mov    bx,bootseg    ;look at 
  1086.     mov    es,bx        ;1st instruct,
  1087.     mov    bx,0        ;must be CLI,
  1088.     cmp    byte ptr es:[bx],0fah
  1089.     mov    bx,offset butstr
  1090.     jne    db4
  1091.  
  1092.     call    boot        ;attempt it,
  1093.     mov    bx,offset dskstr
  1094.  
  1095. db4:    call    pstr
  1096.     jmp    warm
  1097.  
  1098. btbl    db    'f'
  1099.     dw    dd1024
  1100.     dw    offset cgroup:execute
  1101. blen = $ - btbl
  1102.  
  1103.     db    'd'
  1104.     dw    dd1024
  1105.     dw    offset cgroup:execute
  1106.  
  1107.     db    's'
  1108.     dw    sd128
  1109.     dw    offset cgroup:execute
  1110.  
  1111.     db    'h'
  1112.     dw    rms
  1113.     dw    offset cgroup:dtc
  1114.  
  1115.     db    'm'
  1116.     dw    ibm
  1117.     dw    offset cgroup:execute
  1118.  
  1119.     db    0
  1120. page
  1121. ;
  1122. ;get an    address, or use    dump address. If a 
  1123. ;segment is specified, set ES. Return AL =
  1124. ;delimeter character.
  1125. ;
  1126. ;This adds ip_base to BX before    return.    RR 
  1127. ;defaults to 0000 at power up. Does not    affect
  1128. ;dmpoff    so that    setting    RR to 0000 again
  1129. ;correctly displays the    right value.
  1130. ;
  1131. getadr:    mov    ah,1        ;set flag,
  1132.     mov    bx,dmpseg    ;default seg
  1133.     call    inhex        ;if we set seg
  1134.     cmp    al,':'
  1135.     jne    setadr
  1136.         mov    dmpseg,bx ;update ES,
  1137.         mov    ES,bx
  1138.         mov    bx,dmpoff
  1139.         call    inhex    ;then set the 
  1140.         jmp    gtaret    ;address,
  1141. setadr:    dec    ah        ;not seg, if BX
  1142.     jnz    gtaret        ;changed return
  1143.     mov    bx,dmpoff    ;new else get 
  1144. gtaret:    mov    dmpoff,bx    ;old number,
  1145.     test    noreloc,1    ;if flag set,
  1146.     jnz    gtret        ;dont offset.
  1147.     add    bx,ip_base    ;add in    offset,
  1148. gtret:    ret
  1149. ;
  1150. ; type bx as hex, followed by a space.
  1151. ;
  1152. outhex:    call    typehex
  1153.     jmp    o2spc
  1154. typehex:mov    al,bh        ; most first
  1155.     call    out2
  1156.     mov    al,bl        ; do least
  1157.     call    out2
  1158.     ret
  1159. ;
  1160. ;display an address; SSSS:AAAA
  1161. ;
  1162. outadr:    push    bx
  1163.     mov    bx,es        ;print 
  1164.     call    typehex        ;segment:offset
  1165.     mov    al,':'
  1166.     call    charout
  1167.     pop    bx        ;save BX,
  1168.     push    bx
  1169.     sub    bx,ip_base    ;adjust    for
  1170.     call    outhex        ;display,
  1171.     pop    bx        ;restore,
  1172.     ret
  1173. page
  1174. ;
  1175. ;type al as hex.
  1176. ;
  1177. out2:    push    ax
  1178.     push    cx
  1179.     mov    cl,4
  1180.     shr    al,cl
  1181.     pop    cx
  1182.     call    out1h
  1183.     pop    ax
  1184. ;
  1185. ;type lsnybble of al.
  1186. ;
  1187. out1h:    and    al,0fh        ;only ls 4 bits
  1188.     or    al,'0'        ; make ascii
  1189.     cmp    al,'9'+1
  1190.     jb    out1
  1191.     add    al,'a'-'9'-1    ; 0-9,al-f
  1192. out1:    jmp    charout
  1193. ;
  1194. ; output al as hex followed by a space.
  1195. ;
  1196. out2h:    call    out2        ;type al in hex
  1197. ;
  1198. ;type a    space
  1199. ;
  1200. o2spc:    mov    al,' '
  1201.     jmp    out1
  1202. page
  1203. ;
  1204. ;Input a hex  into BX, default the number to 
  1205. ;zero.
  1206. ;
  1207. ghex0:
  1208.     mov    bx,0        ;fall through
  1209. ;
  1210. ;Input a hex number to BX. If only a delimiter 
  1211. ;is typed, return with no change in BX or AH. 
  1212. ;If any    number is input, AH is cleared.    
  1213. ;Supports the following    special    characters:
  1214. ;
  1215. ;    .<reg>    value of register <reg>
  1216. ;    +<xxxx>    sum of current value and 
  1217. ;        additional value <xxxx> + may 
  1218. ;        be entered after any number of 
  1219. ;        digits are typed, including dot
  1220. ;    -    same as    above, except 
  1221. ;        difference of 1st and 2nd value
  1222. ;        (first-second)
  1223. ;    *    Return theproduct of the current
  1224. ;        number and the next entered
  1225. ;        number.
  1226. ;    !    Suppresses relocation of offset
  1227. ;        by GETADR. Cleared on each call.
  1228. ;
  1229. ;Be careful when changing, as it uses 
  1230. ;recursion. Note that 'scratch' stores the LAST
  1231. ;delimiter and is not saved each iteration. 
  1232. ;Jumps to error if anything goes wrong.
  1233. ;
  1234. inhex:    mov    noreloc,0    ;clear flag,
  1235.     call    charin        ;get char 
  1236.     jne    inha        ;exit on CR,
  1237.         jmp    inhret
  1238. inha:    mov    bx,0        ;else seed it
  1239.  
  1240. inhb:    mov    ah,0        ;mark changed.
  1241.     cmp    al,'+'        ;check special 
  1242.     jne    inm        ;chars,    if plus
  1243.         push    bx    ;save current,
  1244.         call    inhex    ;get another,
  1245.         mov    scratch,al ;save delim,
  1246.         pop    ax
  1247.         add    bx,ax    ;add in    new one
  1248. ;splice after "ah,0    "
  1249.         mov    ah,0    ;change flag,
  1250.         mov    al,scratch ;get    delim
  1251.         ret        ;return    now.
  1252.  
  1253. inm:    cmp    al,'-'        ;if minus,
  1254.     jne    instar
  1255.         push    bx    ;save first val
  1256.         call    inhex    ;get second,
  1257.         mov    scratch,al ;save delim
  1258.         mov    ax,bx
  1259.         pop    bx
  1260.         sub    bx,ax    ;first-second,
  1261.         mov    ah,0
  1262.         mov    al,scratch
  1263.         ret
  1264.  
  1265. instar:    cmp    al,'*'        ;if star,
  1266.     jne    indot
  1267.         push    cx    ;save regs,
  1268.         push    dx
  1269.         push    bx    ;save current,
  1270.         call    inhex    ;get next,
  1271.         mov    scratch,al ;save delim,
  1272.         pop    ax    ;get last,
  1273.         mov    cx,bx    ;mult to CX,
  1274.         mul    cx    ;product,
  1275.         mov    bx,ax    ;to BX,
  1276.         pop    dx
  1277.         pop    cx    ;restore,
  1278.         mov    al,scratch
  1279.         mov    ah,0    ;BX changed.
  1280.         ret
  1281.     
  1282. indot:    cmp    al,'.'        ;if dot, use 
  1283.     jne    insup        ;a register,
  1284.         call    regval    ;get reg value,
  1285.         jnc    indot1    ;if not found,
  1286.             jmp    error
  1287. indot1:        mov    ah,0
  1288.         jmp    nxtchr
  1289. insup:    cmp    al,'!'        ;if suprise,
  1290.     jne    notspec
  1291.         mov    noreloc,1 ;suppress off
  1292.         jmp    nxtchr
  1293. notspec:call    hexin        ;digit to hl,
  1294.     jae    nxtchr        ;hex error?
  1295.         jmp    error    ;garbage.
  1296. nxtchr:    call    charin        ;another char 
  1297.     jnz    inhb        ;continue,
  1298.     ret            ;until a delim.
  1299. page
  1300. ;
  1301. ;check the char    in (al)    for hex, return    carry 
  1302. ;if not. install digit into bx.
  1303. ;
  1304. hexin:    sub    al,'0'        ;make hex,
  1305.     jz    hin        ;ok if 0,
  1306.     jb    inhret        ;if .lt. 0,
  1307. hxc:    cmp    al,10        ;do if .le. 9,
  1308.     jb    hin
  1309.     sub    al,27h        ;if a-f, hex.
  1310.     cmp    al,16        ;carry if below
  1311.     cmc            ;now carry if 
  1312.     jb    inhret        ;above,
  1313. hin:
  1314.     add    bx,bx        ;times 16,
  1315.     add    bx,bx
  1316.     add    bx,bx
  1317.     add    bx,bx
  1318.     or    bl,al        ;add in    digit,
  1319.     clc            ;no error.
  1320. inhret:    ret
  1321. ;
  1322. ;Get the ASCII name of a register, and return
  1323. ;it's current value in BX. Return carry set if
  1324. ;not a legal register.
  1325. ;
  1326. regval:    push    si
  1327.     push    cx
  1328.     call    charin        ;get 1st char,
  1329.     mov    ah,al        ;MS byte,
  1330.     call    charin        ;AX is name,
  1331.     cmp    ax,'ip'        ;special case
  1332.     je    retip        ;IP,
  1333.  
  1334.     mov    si,offset regtbl;reg names,
  1335.     mov    bx,offset dmp_ptr; reg values,
  1336.     mov    cx,rtblen
  1337. rv1:    cmp    ax,cs:[si]    ;match?
  1338.     je    rv2        ;go change.
  1339.     add    si,2        ;next...
  1340.     add    bx,2
  1341.     loop    rv1
  1342.     stc            ;not found,
  1343.     jmp    rv3        ;return error.
  1344.  
  1345. rv2:    mov    bx,[bx]        ;get value,
  1346.     clc            ;return good,
  1347. rv3:    pop    cx        ;restore,
  1348.     pop    si
  1349.     ret
  1350. ;
  1351. ;Return the value of IP adjusted by 'ip_base'.
  1352. ;
  1353. retip:    mov    bx,brkip
  1354.     sub    bx,ip_base
  1355.     clc
  1356.     jmp    rv3
  1357. page
  1358. ;
  1359. ;Type ax in binary. 
  1360. ;
  1361. axtobin:mov    cx,16
  1362.     jmp    nnbit
  1363. ;
  1364. ;Type al in binary. Type 1's as 1, 0's as 0.
  1365. ;
  1366. altobin:mov    cx,8
  1367.     mov    ah,al
  1368. nnbit:    mov    dl,'0'
  1369.     shl    ax,1
  1370.     adc    dl,0
  1371.     push    ax
  1372.     mov    al,dl
  1373.     call    charout
  1374.     pop    ax
  1375.     loop    nnbit
  1376.     jmp    o2spc
  1377. ;
  1378. ; print    a string.
  1379. ;
  1380. pstr:    mov    al,cs:[bx]
  1381.     test    al,al
  1382.     je    psret
  1383.     call    charout        ;type until a 0
  1384.     inc    bx
  1385.     jmp    pstr
  1386. ;
  1387. ;do a crlf
  1388. ;
  1389. crlf:    mov    al,cr
  1390.     call    charout
  1391. psret:    ret
  1392. page
  1393. ;
  1394. ;Wait for a character, and return in AL. Leave
  1395. ;the Z bit set if the char is one of our
  1396. ;delimiters. Convert to    lower case.
  1397. ;
  1398. charin:
  1399.     call    INA        ;get one char
  1400.     and    al,7Fh
  1401.     cmp    al,'9'+1    ;to lower 
  1402.     jb    chial        ;case,
  1403.     or    al,20h        ;set shift bit,
  1404. chial:    cmp    al,LF        ;dont echo LF's
  1405.     jz    inaret        ;return    Z set, 
  1406.     push    ax        ;indicate delim
  1407.     call    OUTA        ;echo it,
  1408.     pop    ax
  1409. ;
  1410. ;Here we check for the legal hexadecimal number
  1411. ;delimiters.
  1412. ;
  1413.     cmp    al,CR        ;check delim,
  1414.     jz    inaret
  1415.     cmp    al,','
  1416.     jz    inaret
  1417.     cmp    al,' '
  1418.     jz    inaret
  1419.     cmp    al,LF
  1420.     jz    inaret
  1421.     cmp    al,':'
  1422. inaret:    ret
  1423. ;
  1424. ;Output    a character to the console.
  1425. ;
  1426. charout:
  1427.     cmp    al,CR        ;if CR,    do a LF
  1428.     jnz    out
  1429.     call    out
  1430.     mov    al,LF
  1431. out:    call    OUTA
  1432.     ret
  1433. page
  1434. ;
  1435. ;init each device to the minimum necessary
  1436. ;to run the debugger. The BIOS will fully
  1437. ;init everything once booted.
  1438. ;
  1439. ioinit:    mov    al,8ah        ;8255 0, A out
  1440.     out    ppictl,al    ;B in C0-3 out
  1441.     mov    al,0        ;C4-7 in
  1442.     out    ppia,al        ;outputs off
  1443.  
  1444.     mov    al,1        ;select drive 0
  1445.     out    selp,al        ;for the 1793,
  1446.     mov    al,fintc
  1447.     out    comp,al        ;force interrup
  1448.  
  1449.     mov     al,0Eh
  1450.     call    set8251        ;dummy mode
  1451.     mov     al,40h
  1452.     call    set8251        ;reset 8251 
  1453.     mov     al,4Eh
  1454.     call    set8251        ;8 bt async *16
  1455.     mov     al,37h
  1456.     call    set8251        ;enable Tx & Rx
  1457.     mov     al,0B6h
  1458.     out     pitmode,al    ;ch.2 sq wave 
  1459.     mov     ax,baud
  1460.     out     pittmr2,al    ;low baud rate
  1461.     mov     al,ah 
  1462.     out     pittmr2,al    ;high baud rate
  1463. ;
  1464. ;Setup 8259 Programmable Interrupt Controller
  1465. ;
  1466.     mov     al,13h
  1467.     out     pici1,al    ;8086 mode
  1468.     mov     al,00h
  1469.     out     pici2,al    ;vector
  1470.     mov     al,1Fh
  1471.     out     pici2,al    ;EOI master
  1472.     mov     al,0FFh
  1473.     out     pici2,al    ;all levels off
  1474. page
  1475. ;
  1476. ;Initialize the RMS and DTC86. Do a 
  1477. ;considerable delay here, since I think theres
  1478. ;a problem with the Xebex powering up slowly.
  1479. ;
  1480.     mov    cx,-1
  1481. xdel:    aam
  1482.     loop    xdel
  1483.     call    dskinit    ;init RMS disk,
  1484.     ret
  1485. ;
  1486. ;Set a control byte to the 8251, delaying 
  1487. ;after each one.
  1488. ;
  1489. set8251:
  1490.     out    pcimode,al
  1491.     mov    cx,100
  1492. s8:    jmp    $ + 2
  1493.     loop    s8
  1494.     ret
  1495. page
  1496. ;
  1497. ;Character drivers.
  1498. ;
  1499. ;
  1500. outa:    push     ax
  1501. opoll:    in     al,pcimode
  1502.     and     al,1
  1503.     jz     opoll
  1504.     pop     ax
  1505.     out     pcidata,al
  1506.     ret
  1507. ;
  1508. ;Input a character from the console. Turn
  1509. ;interrupts off, so we can get chars while
  1510. ;MSDOS is running.
  1511. ;
  1512. ina:    pushf
  1513.     cli
  1514. inw:    call     inastat
  1515.     jz     inw
  1516.     in     al,pcidata
  1517.     popf
  1518. inret:    ret
  1519.  
  1520. inastat:
  1521.     in     al,pcimode
  1522.     and     al,2
  1523.     ret
  1524. page
  1525. ;
  1526. ;Play a tune; BX points to a sound table.
  1527. ;
  1528. play:    mov    dx,cs:[bx]    ;get a note,
  1529.     mov    cx,cs:[bx + 2]    ;get duration
  1530.     add    bx,4
  1531.     cmp    dx,ENDNOTE    ;quit if end
  1532.     je    plz
  1533.     call    note
  1534.     jmp    play
  1535. plz:    ret
  1536. ;
  1537. ;Play a note; BX is the divisor, CX is the
  1538. ;duration. If the note is 0, pause.
  1539. ;
  1540. note:    mov    al,0
  1541.     out    ppic,al        ;sound off,
  1542.     cmp    dx,NONOTE    ;if a sound,
  1543.     je    sd1
  1544.     mov    al,36h        ;timer 0 mode 3
  1545.     out    pitmode,al
  1546.     mov    al,dl        ;select sound
  1547.     out    pittmr0,al
  1548.     mov    al,dh
  1549.     out    pittmr0,al
  1550.     mov    al,1
  1551.     out    ppic,al        ;enable sound,
  1552.  
  1553. sd1:    mov    ax,1000
  1554. sd2:    dec    ax        ;delay
  1555.     jnz    sd2
  1556.     loop    sd1
  1557.     mov    al,0        ;disable sound
  1558.     out    ppic,al
  1559.     ret
  1560. page
  1561. ;
  1562. ;Initialize the RMS disk and Xebec controller.
  1563. ;Assumes an RMS 512; this is adequate for
  1564. ;booting the system. The BIOS will init it
  1565. ;for the correct number of tracks, etc.
  1566. ;
  1567. cyls    equ    153        ;cylinders
  1568. heads    equ    8        ;heads,
  1569. comptrk    equ    77        ;precomp trk,
  1570. ecclen    equ    11        ;ECC length,
  1571. ;
  1572. ;initialization tables. These get copied to
  1573. ;RAM, so it can be DMA'd to the DTC.
  1574. ;
  1575. romtbl label byte
  1576.     db    12,0,0,0    ;init drv
  1577.     db    0,0,0,0,0    ;characteristic
  1578. ;
  1579. ;Initialization data.
  1580. ;
  1581.     db    high cyls
  1582.     db    low cyls
  1583.     db    heads
  1584.     db    high comptrk
  1585.     db    low comptrk
  1586.     db    high comptrk
  1587.     db    low comptrk
  1588.     db    ecclen
  1589. tblen equ $ - romtbl
  1590.  
  1591. dskinit:
  1592.     mov    bx,offset cmdtbl ;copy the 
  1593.     mov    si,offset romtbl ;table to RAM
  1594.     mov    cx,tblen    ;so we can DMA
  1595. di1:    mov    al,cs:[si]
  1596.     mov    [bx],al
  1597.     inc    si
  1598.     inc    bx
  1599.     loop    di1
  1600.  
  1601.     in    al,ccr        ;clr old DONE,
  1602.     mov    ax,ds
  1603.     mov    cx,16
  1604.     mul    cx
  1605.     add    ax,offset cmdtbl
  1606.     adc    dx,0
  1607.     out    cal,al
  1608.     mov    al,ah
  1609.     out    cah,al
  1610.     mov    al,dl
  1611.     out    cat,al
  1612.  
  1613.     mov    ax,ds
  1614.     mul    cx
  1615.     add    ax,offset dattbl
  1616.     adc    dx,0
  1617.     out    dal,al
  1618.     mov    al,ah
  1619.     out    dah,al
  1620.     mov    al,dl
  1621.     out    dat,al
  1622.  
  1623.     mov    al,0
  1624.     out    csr,al        ;start it,
  1625.     ret
  1626. page
  1627. ;
  1628. ;Western Digital 1793 Floppy Controller.
  1629. ;Accepts a standard Fido disk table at
  1630. ;DS:BX, performs the function, returns
  1631. ;status in carry and AL.
  1632. ;
  1633. ;
  1634. ;Make our commands and error masks.
  1635. ;
  1636. cread    equ    readc or waitb or mulb
  1637. cwrite    equ    writec or waitb or mulb
  1638. cseek    equ    seekc or updb    ; or stepb
  1639. chome    equ    homec or updb    ; or stepb
  1640. creadh    equ    readh
  1641.  
  1642. readm    equ    sekrb or crcb or ntrdyb 
  1643. writem    equ     sekrb or crcb or wrtrb or wprotb or ntrdyb 
  1644. seekm    equ    ntrdyb or sekrb or crcb
  1645. readhm    equ    readm
  1646.  
  1647. dmawb    equ    64        ;DMA write 
  1648. dmarb    equ    128        ;DMA read 
  1649. dmacb    equ    64h        ;DMA mode bits
  1650. page
  1651. ;
  1652. ;Returns carry clear if the operation was OK,
  1653. ;else the MSDOS error code in AL. No table
  1654. ;parameters are modified. The caller must 
  1655. ;perform diagnostics and retries.
  1656. ;
  1657. ;This driver will read one or more sectors
  1658. ;on a given track. The caller must make
  1659. ;seperate calls for each track read.
  1660. ;
  1661. execute:
  1662.     mov    al,0
  1663.     out    modstp,al    ;stop DMA,
  1664.     call    seldrv        ;select drive,
  1665.     jc    drw15        ;error!
  1666.     in    al,statp    ;if busy,
  1667.     test    al,busyb
  1668.     jz    drw0
  1669.     call    abort        ;abort whatever
  1670.     jc    drw15
  1671. drw0:    call    seek        ;seek to track,
  1672.     jnc    drw1
  1673. drw15:    jmp    fret
  1674. drw1:    mov    ax,sector[bx]     ;set sector,
  1675. ;
  1676. ;Patch location: install a DEC AL here for the
  1677. ;Tecmar non-standard diskettes.
  1678. ;
  1679. wdpatch:sub    al,0
  1680.     out    secp,al
  1681. ;
  1682. ;Make byte count from sector size and sector
  1683. ;count. Adjust for the 8257.
  1684. ;
  1685.     mov    ax,count[bx]    ;count =secsiz*
  1686.     mov    cx,secsiz[bx]    ;#sectors,
  1687.     mul    cx        ;make count,
  1688. page
  1689. ;
  1690. ;Put the count to the 8257, adding in the right
  1691. ;DMA direction bit, depending on the floppy
  1692. ;command.
  1693. ;
  1694. setdma:    and    ax,3fffh    ;max count,
  1695.     dec    ax        ;adjust 
  1696.     out    ch2cp,al    ;out LS byte,
  1697.     cmp byte ptr command[bx],fwrite ;if write,
  1698.     mov    al,dmarb    ;DMA read, else
  1699.     je    setdm
  1700. setr:    mov    al,dmawb    ;DMA write,
  1701. setdm:    or    al,ah        ;add direction,
  1702.     out    ch2cp,al    ;output it,
  1703.  
  1704.     mov    ax,dmaseg[bx]    ;make a 20 bit 
  1705.     mov    cx,16        ;address,
  1706.     mul    cx        ;4 bits in DX,
  1707.     add    ax,dmaoff[bx]    ;add in offset
  1708.     adc    dx,0        ;prop. carry,
  1709.     out    ch2ap,al    ;set,
  1710.     mov    al,ah
  1711.     call    delay        ;delay for 8257
  1712.     out    ch2ap,al
  1713.     mov    al,dl
  1714.     and    al,0fh        ;strip it,
  1715. ;
  1716. ;Ones Complement for Comark MF-85 ONLY.
  1717. ;
  1718.     not    al        ;complement,
  1719.     out    pagep,al    ;select page,
  1720. page
  1721. ;
  1722. ;Execute the command. If 'fcheck', make sure
  1723. ;the header matches the disk type. If all's
  1724. ;well, return carry clear, else carry set and
  1725. ;AL == error code.
  1726. ;
  1727. dorw:    call    exrw        ;execute it,
  1728.     jc    drz        ;error!
  1729.     cmp byte ptr command[bx],fcheck
  1730.     clc            ;if fmt check,
  1731.     jne    drz
  1732.     push    es
  1733.     les    si,dword ptr dmaoff[bx]
  1734.     mov    al,es:[si+3]    ;get sec size,
  1735.     pop    es
  1736.     cmp    al,enn[bx]    ;same?
  1737.     je    drz
  1738.     mov    al,7        ;"media error"
  1739.     stc
  1740. drz:    ret
  1741. ;
  1742. ;Issue the floppy command, wait for DMA done
  1743. ;then check floppy status and abort it. While
  1744. ;we look for DMA done, watch BUSY so we dont
  1745. ;hang. Return carry set and AL == 4 if error.
  1746. ;
  1747. exrw:    mov    al,dmacb
  1748.     out    modstp,al    ;start DMA,
  1749.     
  1750.     mov    al,cread
  1751.     mov    dh,readm
  1752.     cmp    byte ptr command[bx],fread
  1753.     je    sw1
  1754.  
  1755.     mov    al,cwrite    ;get cmd,
  1756.     mov    dh,writem    ;error mask,
  1757.     cmp    byte ptr command[bx],fwrite
  1758.     je    sw1
  1759.  
  1760.     mov    al,creadh
  1761.     mov    dh,readhm
  1762.  
  1763. sw1:    out    comp,al        ;issue it,
  1764. swt:    call    delay        ;delay,
  1765.     in    al,modstp    ;get status,
  1766.     and    al,4        ;if DMA EOP,
  1767.     jnz    retstat        ;return status,
  1768.     in    al,statp    ;check ready 
  1769.     and    al,ntrdyb or busyb ;and busy,
  1770.     cmp    al,busyb
  1771.     je    swt
  1772.  
  1773. retstat:call    delay
  1774.     in    al,statp    ;get status 
  1775.     push    ax        ;save it,
  1776.     call    abort        ;stop it,
  1777.     pop    ax        ;get em back,
  1778.     and    al,dh        ;mask err bits
  1779.     jz    fret        ;ret if zero,
  1780.     test    al,wprotb    ;write prot?
  1781.     mov    al,0
  1782.     jnz    ferr        ;else 
  1783.     mov    al,4        ;DATA ERROR,
  1784. ferr:    stc
  1785. fret:    ret
  1786. page
  1787. ;
  1788. ;Internal seek command. Returns Z set if OK.
  1789. ;Returns carry set and AL error code if error.
  1790. ;
  1791. seek:    mov    ax,curtrk[bx]    ;if at an 
  1792.     cmp    ax,-1        ;unknown trk,
  1793.     je    sk1
  1794.     cmp    ax,0        ;or seek trk 0,
  1795.     jne    sk2
  1796.  
  1797. sk1:    mov    al,chome or l6ms
  1798. sk1a:    call    cmdout        ;recal drive,
  1799.     jc    skz        ;error! else 
  1800.     mov    ax,0        ;current track,
  1801.  
  1802. sk2:    out    trkp,al        ;set cur'nt trk
  1803.     mov    ax,track[bx]    ;seek to trk,
  1804.     out    datp,al
  1805.     mov    al,cseek or l6ms or verb
  1806.     test byte ptr density[bx],2
  1807.     jz    sk2a
  1808.     mov    al,cseek or m6ms or verb
  1809. sk2a:    call    cmdout
  1810.     jc    skz
  1811.     and    al,seekm    ;check error,
  1812.     jz    skz
  1813.     mov    al,6        ;"seek error"
  1814.     stc
  1815. skz:    ret
  1816. page
  1817. ;
  1818. ;Execute the floppy command in AL, return
  1819. ;carry set and AL =2 if not ready, otherwise
  1820. ;return status in AL.
  1821. ;
  1822. cmdout:    out    comp,al        ;issue command,
  1823. cmd1:    call    delay        ;wait for 1791,
  1824.     in    al,statp    ;get status,
  1825.     test    al,ntrdyb    ;chk not rdy,
  1826.     jnz    cmderr
  1827. ;    test    al,busyb    ;busy?
  1828. ;    jz    cmd1
  1829.  
  1830. cmd2:    call    delay
  1831.     in    al,statp    ;wait for
  1832.     test    al,ntrdyb    ;not busy,
  1833.     jnz    cmderr        ;(look for
  1834.     test    al,busyb    ;not rdy)
  1835.     jnz    cmd2
  1836.     ret
  1837.  
  1838. cmderr:    mov    al,2        ;"not ready"
  1839.     stc
  1840.     ret
  1841. page
  1842. ;
  1843. ;Select the disk by changing disk number to a
  1844. ;select bit, and set the density. Make sure 
  1845. ;the drive is ready after the select.
  1846. ;
  1847. seldrv:    mov    cl,drive[bx]    ;get the drive 
  1848.     mov    al,1        ;set drive 0,
  1849.     shl    al,cl        ;make select 
  1850.     test    byte ptr density[bx],1
  1851.     jnz     sl1        ;if single dens
  1852.     or    al,singlb    ;select it,
  1853. sl1:    or    al,patchb    ;fix hardware
  1854.     cmp     word ptr head[bx],0
  1855.     je    sl15
  1856.     or    al,80h        ;2nd head,
  1857. sl15:    test    byte ptr density[bx],2
  1858.     jz    sl3
  1859. ;
  1860. ;Minifloppy. Turn on the motor, and if
  1861. ;the curent track is -1, delay for motor
  1862. ;on. The problem is that we dont know if
  1863. ;the motor was on or not, and we dont want
  1864. ;to delay every time, so this is a quick fix.
  1865. ;
  1866.     or    al,minib    ;mtr on, ready
  1867.     out    selp,al        ;start it,
  1868.     cmp    word ptr curtrk[bx],-1
  1869.     jne    sl3
  1870.  
  1871.     mov    cx,500        ;500 mS delay
  1872. sl2:    call    delay        ;for motor on
  1873.     loop    sl2
  1874.  
  1875. sl3:    out    selp,al        ;select drive,
  1876.     mov    cx,100        ;1mS
  1877. sl4:    call    delay        ;delay,
  1878.     loop    sl4
  1879. ;
  1880. ;Check drive ready. Wait a bit for it to
  1881. ;become ready. Return carry and AL == 2 if
  1882. ;it doesn't.
  1883. ;
  1884. sl5:    mov    cx,5000        ;retries,
  1885. sl6:    call    delay
  1886.     in    al,comp
  1887.     and    al,ntrdyb    ;if ready,
  1888.     jz    slz        ;return,
  1889.     loop    sl6
  1890.     mov    al,2
  1891.     stc
  1892. slz:    ret
  1893. ;
  1894. ;Abort the current operation by issuing a force
  1895. ;interrupt command, and waiting for busy to go 
  1896. ;away.
  1897. ;
  1898. abort:    xor    al,al        ;stop DMA,
  1899.     out    modstp,al
  1900.     mov    al,fintc
  1901. ab1:    mov    cx,1000
  1902.     out    comp,al
  1903. abrt:    call    delay
  1904.     in    al,statp
  1905.     test    al,busyb    ;wait no busy,
  1906.     loopnz    abrt
  1907.     jz    ab2
  1908.     mov    al,12        ;"disk err"
  1909.     stc
  1910. ab2:    ret
  1911. ;
  1912. ;Software delay for use with fast 10MHz 8086's.
  1913. ;
  1914. ;    call    delay        ;19
  1915. delay:    push    cx        ;11
  1916.     mov    cx,15        ;(4 to 8) *15,
  1917. dly:    jmp    $ + 2        ;clear the queue
  1918.     loop    dly        ;17/5
  1919.     pop    cx        ;8
  1920.     ret            ;8
  1921. page
  1922. ;
  1923. ;DTC-86 / Xebec Controller driver. This assumes
  1924. ;an RMS drive attached as drive 0.
  1925. ;Accepts a standard Fido disk table at
  1926. ;DS:BX, performs the function, returns
  1927. ;status in carry and AL.
  1928. ;
  1929. ;
  1930. ;Perform the IO, return carry set and an MSDOS
  1931. ;error code in AL if failure.
  1932. ;
  1933. dtc:    push    ds        ;point ES to
  1934.     pop    es        ;cmd block,
  1935.     push    ds
  1936.     mov    ds,cs:dataloc    ;set DS,
  1937.     mov    ax,ds        ;set cmd addr
  1938.     mov    cx,16
  1939.     mul    cx        ;20 bit addr
  1940.     add    ax,offset xcomand
  1941.     adc    dx,0
  1942.     out    cal,al        ;out 3 bytes,
  1943.     call    delay
  1944.     mov    al,ah
  1945.     out    cah,al
  1946.     call    delay
  1947.     mov    al,dl
  1948.     out    cat,al
  1949.     call    delay
  1950.  
  1951.     mov    ax,es:dmaseg[bx]
  1952.     mul    cx        ;same for data
  1953.     add    ax,es:dmaoff[bx]
  1954.     adc    dx,0
  1955.     out    dal,al        ;out 3 bytes,
  1956.     call    delay
  1957.     mov    al,ah
  1958.     out    dah,al
  1959.     call    delay
  1960.     mov    al,dl
  1961.     out    dat,al
  1962.     call    delay
  1963. page
  1964. ;
  1965. ;Calculate the logical sector, put it in the
  1966. ;table.
  1967. ;
  1968.     mov    ax,es:track[bx]    ;AX= track,
  1969.     mov    dx,0
  1970.     mul word ptr es:spt[bx]    ; *SPT,
  1971.     mov    cx,es:sector[bx]
  1972.     dec    cx        ;make 0-N,
  1973.     add    ax,cx
  1974.     adc    dx,0
  1975.  
  1976.     mov    lowaddr,al    ;store low,
  1977.     mov    hiaddr,ah    ;high sec,
  1978.     and    dl,0fh        ;top sec,
  1979.  
  1980.     mov    al,es:drive[bx]    ;make LUN,
  1981.     mov    cl,5
  1982.     shl    al,cl
  1983.     or    al,dl        ;add in,
  1984.     mov    lun,al        ;store it,
  1985.  
  1986.     mov    control,4     ;type =RMS,
  1987.     mov    ax,es:count[bx]
  1988.     mov    scount,al     ;set sec count,
  1989.  
  1990.     mov    al,es:command[bx]
  1991. ;    mov    xcomand,xwrite
  1992. ;    cmp    al,fwrite
  1993. ;    je    dtc1
  1994.     mov    xcomand,xread
  1995.     cmp    al,fread
  1996.     je    dtc1
  1997.     mov    xcomand,xcheck
  1998.     cmp    al,fcheck
  1999.     je    dtc1
  2000.     stc            ;illegal cmd
  2001.     jmp    dtc3
  2002.  
  2003. dtc1:    in    al,ccr        ;clear old done
  2004.     mov    al,0
  2005.     out    csr,al        ;start it,
  2006.  
  2007. dtc2:    call    delay
  2008.     in    al,csr        ;wait for DONE,
  2009.     test    al,80h
  2010.     jz    dtc2
  2011.     call    delay
  2012.     in    al,ccr        ;sample ERROR,
  2013.     and    al,2        ;clears DONE,
  2014.     jz    dtc3
  2015.     stc            ;error!
  2016. dtc3:    pop    ds
  2017.     ret
  2018.  
  2019. code ends
  2020.  
  2021.     end    bugger
  2022.